#include"models.cpp"
#include"collision.cpp"

Point3D camera;
Vector3D horizontal,vertical,in;

void init()
{
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
  glutInitWindowPosition(0, 0);
  glutInitWindowSize(screen_width, screen_height);
  glutCreateWindow("Collision Engine");

	glEnable(GL_LIGHTING);
  	glEnable(GL_LIGHT0);
  	glShadeModel(GL_SMOOTH);
  	glEnable(GL_DEPTH_TEST);
  	glEnable(GL_NORMALIZE);

	glClearColor(0.1, 0.1, 0.1, 0);

  	GLfloat mat_ambient[] = {0.7, 0.7, 0.7, 1};
  	GLfloat mat_diffuse[] = {1, 1, 1, 1};
  	GLfloat mat_specular[] = {1, 1, 1, 1};
  	GLfloat mat_shininess[] = {50};
  	glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
  	glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
  	glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
  	glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);

	GLfloat light_intensity[] = {1, 1, 1, 1};
	GLfloat light_position[] = {0.5, 1, 1, 0};
  	glLightfv(GL_LIGHT0, GL_POSITION, light_position);
  	glLightfv(GL_LIGHT0, GL_DIFFUSE, light_intensity);

  	glMatrixMode(GL_PROJECTION);
  	glLoadIdentity();
    //glOrtho(0, 5*aspect_ratio, 0, 5, 0, 100);
    gluPerspective(45,aspect_ratio,1,1000);
  	glMatrixMode(GL_MODELVIEW);
  	glLoadIdentity();
  	//gluLookAt(0, 0, 8, -1, -1, 0, 0, 1, 0);
    //gluLookAt(0, 0, 9, 0, 0, 0, 0, 1, 0);
    gluLookAt(camera.x, camera.y, camera.z, camera.x+in.x, camera.y+in.y, camera.z+in.z, vertical.x, vertical.y, vertical.z);

	glViewport(0, 0, screen_width, screen_height);
}


void draw_axis()
{
	GLfloat mat_ambient[] = {0.7, 0.7, 0.7, 1};
	GLfloat mat_diffuse[] = {0.2, 1, 0.2, 1};
  GLfloat mat_specular[] = {1, 1, 1, 1};
  GLfloat mat_shininess[] = {50};
  glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
  glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
  glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
  glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
	GLUquadric *quadric = gluNewQuadric();
	//green z-axis
  glPushMatrix();
	gluCylinder(quadric, 0.05, 0.05, 150, 12, 12);
  glTranslatef(7,0,0);
  gluCylinder(quadric, 0.05, 0.05, 9, 12, 12);  
  glTranslatef(0,5,0);
  gluCylinder(quadric, 0.05, 0.05, 9, 12, 12);  
  glTranslatef(-7,0,0);
  gluCylinder(quadric, 0.05, 0.05, 9, 12, 12);
  glPopMatrix();

	mat_diffuse[0] = 1;
	mat_diffuse[1] = 0.2;
	mat_diffuse[2] = 0.2;

  glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
  glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
  glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
  glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
 
	//red x axis
  glPushMatrix();
  glRotatef(90,0,1,0);
	gluCylinder(quadric, 0.05, 0.05, 150, 12, 12);
  glTranslatef(-9,0,0);
  gluCylinder(quadric, 0.05, 0.05, 7, 12, 12);
  glTranslatef(0,5,0);
  gluCylinder(quadric, 0.05, 0.05, 7, 12, 12);
  glTranslatef(9,0,0);
  gluCylinder(quadric, 0.05, 0.05, 7, 12, 12);
  glPopMatrix();
  mat_diffuse[0] = 0.2;
  mat_diffuse[1] = 0.2;
  mat_diffuse[2] = 1;

  glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
  glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
  glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
  glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
  
  //blue y axis
  glPushMatrix();
  glRotatef(-90,1,0,0);
  gluCylinder(quadric, 0.05, 0.05, 150, 12, 12);
  glTranslatef(7,0,0);
  gluCylinder(quadric, 0.05, 0.05, 5, 12, 12);
  glTranslatef(0,-9,0);
  gluCylinder(quadric, 0.05, 0.05, 5, 12, 12);
  glTranslatef(-7,0,0);
  gluCylinder(quadric, 0.05, 0.05, 5, 12, 12);
  glPopMatrix();
  mat_diffuse[0] = 1;
  mat_diffuse[1] = 1;
  mat_diffuse[2] = 1;

  glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
  glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
  glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
  glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
}
void move_all(GLfloat time){
  for(int i=0; i< w_pointer->no_spheres; i++)
    w_pointer->spheres[i].move(time);

}

void simulate(){
  prev_time = next_time;
  next_time = clock();

  GLfloat time_difference = float(next_time - prev_time)/CLOCKS_PER_SEC;
  vector< FirstCollidingPair > first_colliding_pairs = Collision::get_FirstCollidingPairs(time_difference);
  vector< FirstCollidingPair > :: iterator iter;

  while(first_colliding_pairs.size()){

    move_all(first_colliding_pairs[0].time_to_collide);
    time_difference -= first_colliding_pairs[0].time_to_collide;
    for(iter=first_colliding_pairs.begin(); iter!=first_colliding_pairs.end(); iter++ ){
      switch(iter->collision_type){

        case WALL_SPHERE  : Collision::collision_response(w_pointer->walls[iter->first_index], w_pointer->spheres[iter->second_index]);
                            break;
        case SPHERE_SPHERE: Collision::collision_response(w_pointer->spheres[iter->first_index],w_pointer->spheres[iter->second_index]);
                            break;
        case SPHERE_SLAB : Collision::collision_response(w_pointer->spheres[iter->first_index],*player);
                            break;                    
      }
    }

    first_colliding_pairs = Collision::get_FirstCollidingPairs(time_difference);

  }
  for(int i=0; i<w_pointer->no_spheres; i++){
    Point3D center = w_pointer->spheres[i].get_center();
    GLfloat r = w_pointer->spheres[i].get_radius();

    if (center.x - r < 0){
      printf("\n\nGAME OVER...!!!\n\n");
      sleep(5);
      exit(0);
    }

    //if(center.x < 0 ||center.x > 7 || center.y < 0 || center.y > 5 || center.z < 0 || center.z > 9)
    //  w_pointer->spheres[i].set_center(Point3D( (center.x > 0 && center.x < 7 ? center.x:(center.x<0?r:7-r)),
    //                                            (center.y > 0 && center.y < 5 ? center.y:(center.y<0?r:5-r)),
    //                                            (center.z > 0 && center.z < 9 ? center.z:(center.z<0?r:9-r))  ));
  }    
  move_all(time_difference);
  glutPostRedisplay();

//  w_pointer->spheres[0].print_center();
//  sleep(1);
}

void draw()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

 	glPushMatrix();
  gluLookAt(camera.x, camera.y, camera.z, camera.x+in.x, camera.y+in.y, camera.z+in.z, vertical.x, vertical.y, vertical.z);
  glPushMatrix();
  player->draw();
  glPopMatrix();
	draw_axis();
  for(int i=0; i< w_pointer->no_spheres; i++){
    glPushMatrix();
    w_pointer->spheres[i].draw();
    glPopMatrix();
  }
  glPopMatrix();
	glutSwapBuffers();

}
void processKeys(unsigned char key, int x, int y) {
  switch(key){
    case 'w':glTranslatef(0,-0.1,0); break;
    case 's':glTranslatef(0,0.1,0); break;
    case 'a':glTranslatef(0.1,0,0); break;
    case 'd':glTranslatef(-0.1,0,0); break;
    case '=':
    case '+':glTranslatef(0,0,0.1); break;
    case '_':
    case '-':glTranslatef(0,0,-0.1); break;

    case 'i':glRotatef(2,1,0,0); break;
    case 'k':glRotatef(-2,1,0,0); break;

    case 'j':glRotatef(2,0,1,0); break;
    case 'l':glRotatef(-2,0,1,0); break;

    case 'u':glRotatef(2,0,0,1); break;
    case 'o':glRotatef(-2,0,0,1); break;

    case 't': if(player->get_center().y < 4)
                player->set_center_y_z(player->get_center().y+0.1,player->get_center().z);
            break;

    case 'g':if(player->get_center().y > 1)
                player->set_center_y_z(player->get_center().y-0.1,player->get_center().z);
            break;

    case 'f': if(player->get_center().z < 8)
                player->set_center_y_z(player->get_center().y,player->get_center().z+0.1);
            break;

    case 'h':if(player->get_center().z > 1)
                player->set_center_y_z(player->get_center().y,player->get_center().z-0.1);
            break;
  }
}
int main(int argc, char *argv[])
{
  Slab S(Point3D(0,2.5,4.5),Vector3D(0,0,0));
  player=&S;
  camera = Point3D(3.5, 2.5, 12);
  in = Vector3D(0,0,-12);
  horizontal = Vector3D(1,0,0);
  vertical = Vector3D(0,1,0);
  next_time = clock();
  World world;
  world.get_world_from_file();
  w_pointer = &world;
	screen_width=700;
	screen_height=500;
	aspect_ratio=screen_width/screen_height;
	glutInit(&argc,argv);
	init();
	glutDisplayFunc(draw);
	glutIdleFunc(simulate);
  glutKeyboardFunc(processKeys);
	glutMainLoop();
	return 0;
}
